﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Threading.Tasks;
using KC.Business.Processor;
using KC.DataAccess.Processor;

namespace KC.Business.Processor.Plugins.JobProcessors
{
	public class RssProcessor : ProcessorBase
	{
		public override bool Run()
		{
			try {
				UpdateRssFeeds();
				return true; }
			catch (Exception ex) {
				LogError(ex);
				return false; }
		}
		private void UpdateRssFeeds()
		{
			try {
				int numChans = 0;
				foreach (RssChannel chan in dc.RssChannels)  {
					string detail = "";
					try {
						detail = DownloadNewItems(chan);
						numChans++; }
					catch (Exception ex) {
						detail = ex.Message;
						LogError(ex); }
					AddDetail(detail); }
				AddDetail("  " + numChans.ToString() + " of " + dc.RssChannels.Count().ToString() + " channels downloaded.");
				dc.SubmitChanges(); }
			catch (Exception ex) { LogError(ex); }
		}

		public string DownloadNewItems(RssChannel chan)
		{
			string result = "";
			DateTime dtOldest = DateTime.MinValue;
			var items = from ri in dc.RssItems orderby ri.ID descending select ri;
			if (items.Count() > 0)
				dtOldest = items.First().pubDate;
			result = " Downloading new items from " + chan.Title.Trim() + "...\r\n";
			result += "  Last known post was " + dtOldest.ToString("MM/dd/yy HH:mm:ss") + "\r\n";

			// Download the item feed; Find and parse individual RssItems
			string xml = new System.Net.WebClient().DownloadString(chan.RssURL);
			XmlDocument xdoc = new XmlDocument();
			xdoc.LoadXml(xml);

			// Loop through items in this channel and insert them
			XmlNodeList nodes = xdoc.SelectNodes(@"/rss/channel/item");
			result += "  " + nodes.Count.ToString() + " nodes downloaded from " + chan.RssURL + " \r\n";
			int ItemsDownloaded = 0;
			foreach (XmlNode node in nodes)
			{
				if (node.Name.ToLower() != "item")
					continue;
				RssItem item = ParseItem(node);
				item.RssChannelID = chan.ID;
				if ((from ri in dc.RssItems where ri.URL == item.URL select ri).Count() == 0)
				{
					dc.RssItems.InsertOnSubmit(item);
					ItemsDownloaded++;
				}
			}
			dc.SubmitChanges();
			result += "  " + ItemsDownloaded.ToString() + " of " + nodes.Count.ToString() + " inserted.\r\n";
			return result;
		}
		public static RssChannel ParseChannel(string RssURL, XmlDocument xdoc)
		{
			RssChannel chan = new RssChannel();
			chan.Title = xdoc.SelectSingleNode(@"/rss/channel/title") == null ? "" : xdoc.SelectSingleNode(@"/rss/channel/title").InnerText.Trim();
			chan.ImageURL = xdoc.SelectSingleNode(@"/rss/channel/image/url") == null ? "" : xdoc.SelectSingleNode(@"/rss/channel/image/url").InnerText.Trim();
			chan.Description = xdoc.SelectSingleNode(@"/rss/channel/description") == null ? "" : xdoc.SelectSingleNode(@"/rss/channel/description").InnerText.Trim();
			chan.Link = xdoc.SelectSingleNode(@"/rss/channel/link") == null ? "" : xdoc.SelectSingleNode(@"/rss/channel/link").InnerText.Trim();
			chan.PubDate = xdoc.SelectSingleNode(@"/rss/channel/pubDate") == null ? DateTime.Now : DateTime.Parse(xdoc.SelectSingleNode(@"/rss/channel/pubDate").InnerText.Trim());
			chan.RssURL = RssURL;
			return chan;
		}
		private static RssItem ParseItem(XmlNode node)
		{
			RssItem item = new RssItem();
			if (node.SelectSingleNode(@"title") == null)
				return null;

			item.Title = node.SelectSingleNode(@"title") == null ? "" : node.SelectSingleNode(@"title").InnerText.Trim();
			item.Description = node.SelectSingleNode(@"description") == null ? "" : node.SelectSingleNode(@"description").InnerText.Trim().Replace("<![CDATA[", "").Replace("]]>", "");
			item.CommentsURL = node.SelectSingleNode(@"comments") == null ? "" : node.SelectSingleNode(@"comments").InnerText.Trim();
			item.URL = node.SelectSingleNode(@"link") == null ? "" : node.SelectSingleNode(@"link").InnerText.Trim();
			DateTime pubDate = DateTime.Now;
			if (node.SelectSingleNode(@"pubDate") != null)
				DateTime.TryParse(node.SelectSingleNode(@"pubDate").InnerText.Trim(), out pubDate);
			if (pubDate < DateTime.Parse("01/01/2000"))
				pubDate = DateTime.Now;
			item.pubDate = pubDate;
			return item;
		}
	}
}
